package offical.baseClass

/**
 * 类 =  类名+类头（构造方法）+类体，其中类头和类体可省略
 * 一个类可以有一个主构造函数和一个或多个次构造函数。主构造函数是类头的一部分：它跟在类名（和可选的类型参数）后
 * 如果主构造函数没有任何注解或者可见性修饰符，可以省略这个 constructor 关键字。
 */
class OrderInitDemo(name: String) { //注意，这里没有val,var 仅仅作为主构造方法的参数

    val firstProperty = "FirstProperty:$name".also(::println)

    init {
        println("First init block that print $name")
    }

    val secondProperty = "SecondProperty:$name".also(::println)

    init {
        println("Second init block that print $name")
    }

}

annotation class inject
//如果构造方法需要有注解或可见性修饰符，这个 constructor 关键字是必需的
class CustomClass @inject protected constructor(name: String)

//类的属性直接在主构造函数中初始化
class PersonBean(val id: Long, val name: String, val age: Int)

/**
 * 如果类有一个主构造函数，每个次构造函数需要委托给主构造函数
 * 委托到同一个类的另一个构造函数用 this 关键字
 */
class SecondaryConstructor1(val age: Int, val personBean: PersonBean) {

    /**
     * 次构造函数不能有声明 val 或 var
     */
    constructor(age: Int, personBean: PersonBean, id: Long) : this(age, personBean)

}

/**
 * 以下两种区别在于类中是否包含有id和name两个属性
 */
class SecondaryConstructor2(id: Long, name: String)

class SecondaryConstructor3(val id: Long, val name: String)

/**
 * 如果默认要有无参构造和有参构造共存,必须没有主构造函数
 */
class SecondaryConstructor4 {

    private var id: Long? = 0

    /**
     * 注意这里没有主构造函数，但还是会隐式调用init
     */
    init {
        println("SecondaryConstructor4 init")
    }

    constructor() {
        println("SecondaryConstructor4 noParams")
    }

    constructor(id: Long) {
        this.id = id
    }

    constructor(id: Long, name: String) : this(id) {
        "$id and $name".also(::println)
    }
}

/**
 * 在 JVM 上，如果主构造函数的所有的参数都有默认值，编译器会生成 一个额外的无参构造函数，它将使用默认值。
 */
class SecondaryConstructor5(val name: String = "石沉大海")


fun main(args: Array<String>) {
    val s = OrderInitDemo("67373")
    s.firstProperty
    s.secondProperty

    SecondaryConstructor4()
    println(SecondaryConstructor5().name)

}